﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Configuration;
using System.IO;
using System.Net;
using System.Reflection;
using System.Text;
using System.Web;
using System.Web.Script.Serialization;
using System.Xml;
using System.Diagnostics;
using Vbyte.DataSource.Utility;
using Vbyte.Configuration;
using Vbyte.Extension;

namespace Vbyte.DataSource.Data
{
    /// <summary>
    /// JSON数据转换功能函数
    /// </summary>
    public static class JsonExchange
    {
        /// <summary>
        /// 调试辅助
        /// </summary>
        /// <param name="logFileName">日志文件名，不包含扩展名。</param>
        /// <param name="writer">记录日志方法</param>
        public static void Log(string logFileName, Action<TextWriter> writer)
        {
            bool blnDoLog = true;
            string Topic = "操作日志";
            string key = "DataSource.LogToDB";
            bool blnUseDbLog = (!string.IsNullOrEmpty(ConfigurationManager.AppSettings[key])
                    && Convert.ToBoolean(ConfigurationManager.AppSettings[key]));

            if (logFileName.IndexOf("api", StringComparison.InvariantCultureIgnoreCase) != -1)
            {
                key = "DataSource.LogApiData";
                Topic = "API操作日志";
                blnDoLog = (!string.IsNullOrEmpty(ConfigurationManager.AppSettings[key])
                    && Convert.ToBoolean(ConfigurationManager.AppSettings[key]));
            }

            if (logFileName.IndexOf("json", StringComparison.InvariantCultureIgnoreCase) != -1)
            {
                key = "DataSource.LogJsonData";
                Topic = "JSON操作日志";
                blnDoLog = (!string.IsNullOrEmpty(ConfigurationManager.AppSettings[key])
                    && Convert.ToBoolean(ConfigurationManager.AppSettings[key]));
            }

            if (blnDoLog)
            {
                int iSkipFrame = 5;
                if (!blnUseDbLog)
                {
                   //Util.Common.Log(logFileName, false, iSkipFrame, ".txt", writer);
                }
                else
                {
                    StringWriter sw = new StringWriter();
                    StackFrame invokeFrame = new StackFrame(iSkipFrame);
                    MethodBase method = invokeFrame.GetMethod();
                    string invokeTypeName = method.ReflectedType.IsGenericType ?
                        method.ReflectedType.FullName.Replace("`1", "<" + method.ReflectedType.GetGenericArguments()[0].ToString() + ">")
                        : method.ReflectedType.FullName;

                    sw.WriteLine("Invoke By: {0}::{1}", invokeTypeName, method.Name);
                    writer(sw);
                    //new SystemLog
                    //{
                    //    Category = logFileName.StartsWith("error", StringComparison.InvariantCultureIgnoreCase) ? "ERROR" : "INFO",
                    //    Topic = Topic,
                    //    LogTypeName = invokeTypeName,
                    //    Message = sw.ToString()
                    //}.Insert();
                }
            }

        }

        #region 功能函数
        /// <summary>
        /// 获取JSON数据的词典格式
        /// </summary>
        /// <param name="jsonData">JSON字符串</param>
        /// <returns></returns>
        public static Dictionary<string, object> GetObjectDictionary(string jsonData)
        {
            JavaScriptSerializer jss = new JavaScriptSerializer();
            object jObj = jss.DeserializeObject(jsonData);
            if (jObj == null)
            {
                return new Dictionary<string, object>();
            }
            else
            {
                return jObj as Dictionary<string, object>;
            }
        }

        /// <summary>
        /// 输出实例的属性值
        /// </summary>
        /// <typeparam name="T">实例类型</typeparam>
        /// <param name="instance">当前实例</param>
        /// <param name="writer">文本输出器</param>
        public static void Dump<T>(this T instance, TextWriter writer)
        {
            if (instance == null) return;
            Type t = instance.GetType();
            PropertyInfo[] pis = t.GetProperties();
            foreach (PropertyInfo pi in pis)
            {
                writer.Write("{");
                writer.Write("Name:{0}", pi.Name);
                writer.Write(",Type:{0}", pi.PropertyType);
                if (pi.CanRead)
                {
                    writer.Write(",CandRead:true,Value:{0}", pi.GetGetMethod().Invoke(instance, null));
                }
                if (pi.CanWrite)
                {
                    writer.Write(",CandWrite:true");
                }
                writer.WriteLine("}");
            }
        }


        /// <summary>
        /// 以毫秒为单位的运行时间
        /// </summary>
        /// <typeparam name="TResult">返回值类型</typeparam>
        /// <param name="ms">运行毫秒数</param>
        /// <param name="fun">要运行的相关函数及参数委托</param>
        /// <returns></returns>
        public static TResult GetRunTimeMilliseconds<TResult>(ref long ms, Func<TResult> fun)
        {
            System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
            sw.Start();
            TResult result = fun();
            sw.Stop();
            ms = sw.ElapsedMilliseconds;
            return result;
        }

        /// <summary>
        /// 以毫秒为单位的运行时间
        /// </summary>
        /// <param name="act">计算一个不带参数的函数的运行时间</param>
        /// <returns>运行毫秒数</returns>
        public static long GetRunTimeMilliseconds(Action act)
        {
            System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
            sw.Start();
            act();
            sw.Stop();
            return sw.ElapsedMilliseconds;
        }


        /// <summary>
        /// 判定是否是错误代码的json结果
        /// </summary>
        /// <param name="jsonResult">json原始返回数据</param>
        public static bool IsErrorCodeResult(string jsonResult)
        {
            if (string.IsNullOrEmpty(jsonResult))
            {
                return false;
            }
            else
            {
                return jsonResult.StartsWith("{\"errorcode\":");
            }
        }

        /// <summary>
        /// 获取对象的URL参数传递方式
        /// </summary>
        /// <param name="objParam"></param>
        /// <returns></returns>
        public static string ToQueryString(this object objParam)
        {
            if (objParam == null) return string.Empty;
            Type t = objParam.GetType();
            StringBuilder sb = new StringBuilder();
            bool firstAppend = true, blnAppend = false;
            object mValue = null;
            foreach (PropertyInfo pi in t.GetProperties())
            {
                blnAppend = false;
                mValue = pi.GetGetMethod().Invoke(objParam, null);
                if (pi.DeclaringType.IsValueType)
                {
                    //Nullable<T>
                    if (pi.DeclaringType.IsGenericType
                        && pi.DeclaringType.GetGenericTypeDefinition().Equals(typeof(Nullable<>).GetGenericTypeDefinition()))
                    {
                        if (mValue == null) blnAppend = false;
                    }
                    else
                    {
                        blnAppend = true;
                    }
                }
                else
                {
                    if (mValue != null) blnAppend = true;
                }

                if (blnAppend == true)
                {
                    if (firstAppend)
                    {
                        sb.AppendFormat("{0}={1}", pi.Name, HttpUtility.UrlEncode(mValue.ToString()));
                        firstAppend = false;
                    }
                    else
                    {
                        sb.AppendFormat("&{0}={1}", pi.Name, HttpUtility.UrlEncode(mValue.ToString()));
                    }
                }
            }
            return sb.ToString();
        }

        /// <summary>
        /// 获取命名参数数据集合的url查询数据
        /// </summary>
        public static string ToQueryString(this NameValueCollection query)
        {
            if (query == null) return string.Empty;
            StringBuilder sb = new StringBuilder();
            bool firstAppend = true;
            foreach (string key in query.Keys)
            {
                if (firstAppend)
                {
                    sb.AppendFormat("{0}={1}", key, HttpUtility.UrlEncode(query[key]));
                    firstAppend = false;
                }
                else
                {
                    sb.AppendFormat("&{0}={1}", key, HttpUtility.UrlEncode(query[key]));
                }
            }
            return sb.ToString();
        }


        /// <summary>
        /// 输出带缩进格式的XML文档
        /// </summary>
        /// <param name="xDoc">XML文档对象</param>
        /// <param name="writer">文本输出器</param>
        public static void WriteIndentedXml(XmlDocument xDoc, TextWriter writer)
        {
            XmlTextWriter xWriter = new XmlTextWriter(writer);
            xWriter.Formatting = Formatting.Indented;
            xDoc.WriteContentTo(xWriter);
        }
        #endregion

        #region 远程数据获取功能函数

        /// <summary>
        /// 获取远程接口的JSON数据
        /// </summary>
        /// <param name="url">不带参数的接口URL地址</param>
        /// <param name="query">查询字符串命名对象</param>
        /// <returns></returns>
        public static string GetApiJson(string url, NameValueCollection query)
        {
            using (HttpClient client = new HttpClient())
            {
                client.Encoding = Encoding.UTF8;
                client.Headers.Add(HttpRequestHeader.UserAgent, "Gw-DataExchange/1.0");
                client.QueryString = query;

                long downMs = 0;
                string apiRaw = JsonExchange.GetRunTimeMilliseconds<string>(ref downMs,
                     new Func<string>(delegate() { return client.DownloadString(url); })
                 );

                lock (typeof(JsonExchange))
                {
                    Log("API-" + DateTime.Now.ToString("yyyy-MM-dd"), sw =>
                    {
                        sw.WriteLine("完成加载数据：{0}", url);
                        if (query != null)
                        {
                            sw.WriteLine("参数：{0}", query.ToQueryString());
                        }
                        sw.WriteLine("下载数据所花时间：{0}ms", downMs);
                        sw.WriteLine("########## 原始数据开始 ##########");
                        sw.WriteLine(apiRaw);
                        sw.WriteLine("########## 原始数据结束 ##########");
                        sw.WriteLine();
                        sw.Close();
                    });
                }

                return apiRaw;

                /*
                #if UnitTest
                long downMs = 0;
                string apiRaw = JsonExchange.GetRunTimeMilliseconds<string>(ref downMs,
                     new Func<string>(delegate() { return client.DownloadString(url); })
                 );

                Console.WriteLine("---UnitTest---");
                Console.WriteLine("完成加载数据：{0}", url);
                if (query != null)
                {
                    Console.WriteLine("参数：{0}", query.ToQueryString());
                }
                Console.WriteLine("下载数据所花时间：{0}ms", downMs);
                Console.WriteLine("########## 原始数据开始 ##########");
                Console.WriteLine(apiRaw);
                Console.WriteLine("########## 原始数据结束 ##########");
                Console.WriteLine();
                return apiRaw;

                #else

                return client.DownloadString(url);

                #endif
                */

            }
        }
        #endregion
    }
}
